--- /dev/null
+/*
+
+ Support for Swiss Map 50 (.xol) format
+
+ Copyright (C) 2007 Olaf Klein, o.b.klein@gpsbabel.org
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA
+
+*/
+
+#include "defs.h"
+#include "xmlgeneric.h"
+#include "jeeps/gpsmath.h"
+#include "garmin_tables.h"
+
+static waypoint *wpt;
+static route_head *trk;
+static gbfile *fout;
+static int space;
+static bounds all_bounds;
+static short_handle short_h;
+
+static arglist_t xol_args[] =
+{
+ ARG_TERMINATOR
+};
+
+#define MYNAME "xol"
+
+#if ! HAVE_LIBEXPAT
+void
+xol_rd_init(const char *fname)
+{
+ fatal(MYNAME ": This build excluded \"" MYNAME "\" support because expat was not installed.\n");
+}
+
+void
+xol_read(void)
+{
+}
+
+#else
+
+static xg_callback xol_shape, xol_shape_end;
+static xg_callback xol_waypt, xol_overlay;
+
+#define XOL "/overlays/overlay"
+
+static
+xg_tag_mapping xol_map[] = {
+ { xol_overlay, cb_start, XOL },
+ { xol_shape, cb_start, XOL "/shapes/*shape" },
+ { xol_shape_end, cb_end, XOL "/shapes/*shape" },
+ { xol_waypt, cb_start, XOL "/shapes/shape/*points/point" },
+ { NULL, 0, NULL }
+};
+
+
+static void
+xol_overlay(const char *args, const char **attrv)
+{
+ const char **avp = &attrv[0];
+
+ while (*avp) {
+ if (strcmp(avp[0], "version") == 0) {
+ if (strcmp(avp[1], "1.0") != 0)
+ fatal(MYNAME ": Unsupported version %s.\n", avp[1]);
+ }
+
+ avp+=2;
+ }
+}
+
+static void
+xol_shape(const char *args, const char **attrv)
+{
+ const char **avp = &attrv[0];
+
+ while (*avp) {
+ if (strcmp(avp[0], "type") == 0) {
+ if (strcmp(avp[1], "waypoint") == 0) {
+ wpt = waypt_new();
+ }
+ else if (strcmp(avp[1], "polyline") == 0) {
+ trk = route_head_alloc();
+ track_add_head(trk);
+ }
+ }
+ else if (strcmp(avp[0], "name") == 0) {
+ if (wpt) wpt->shortname = xstrdup(avp[1]);
+ else if (trk) trk->rte_name = xstrdup(avp[1]);
+ }
+ else if (strcmp(avp[0], "comment") == 0) {
+ if (wpt) wpt->notes = xstrdup(avp[1]);
+ }
+ else if (strcmp(avp[0], "alt") == 0) {
+ if (wpt) wpt->altitude = atof(avp[1]);
+ }
+ else if (strcmp(avp[0], "timestamp") == 0) {
+ if (wpt) wpt->creation_time = xml_parse_time(avp[1], &wpt->microseconds);
+ }
+ else if (strcmp(avp[0], "icon") == 0) {
+ if (wpt) {
+ wpt->icon_descr = xstrdup(avp[1]);
+ wpt->wpt_flags.icon_descr_is_dynamic = 1;
+ }
+ }
+
+ avp+=2;
+ }
+}
+
+static void
+xol_shape_end(const char *args, const char **unused)
+{
+ if (wpt) {
+ if (trk) track_add_wpt(trk, wpt);
+ else waypt_add(wpt);
+ wpt = NULL;
+ }
+ else if (trk) {
+ if (trk->rte_waypt_ct == 0) track_del_head(trk);
+ trk = NULL;
+ }
+}
+
+static void
+xol_waypt(const char *args, const char **attrv) {
+ const char **avp = &attrv[0];
+ int x, y;
+
+ while (*avp) {
+ if (strcmp(avp[0], "y") == 0)
+ y = atoi(avp[1]);
+ else if (strcmp(avp[0], "x") == 0)
+ x = atoi(avp[1]);
+ avp+=2;
+ }
+
+ GPS_Math_CH1903_NGEN_To_WGS84((double)x, (double)y, &wpt->latitude, &wpt->longitude);
+}
+
+static void
+xol_rd_init(const char *fname)
+{
+ trk = NULL;
+ wpt = NULL;
+
+ xml_init(fname, xol_map, NULL);
+}
+
+static void
+xol_read(void)
+{
+ xml_read();
+}
+
+#endif
+
+static void
+xol_rd_deinit(void)
+{
+ xml_deinit();
+}
+
+/* writer */
+
+static void
+xol_fatal_outside(const waypoint *wpt)
+{
+ gbfprintf(fout, "#####\n");
+ fatal(MYNAME ": %s (%s) is outside of convertable area \"%s\"!\n",
+ wpt->shortname ? wpt->shortname : "Waypoint",
+ pretty_deg_format(wpt->latitude, wpt->longitude, 'd', NULL, 0),
+ gt_get_mps_grid_longname(grid_swiss, MYNAME));
+}
+
+
+static void
+xol_write_time(const waypoint *wpt)
+{
+ char time_string[64];
+
+ xml_fill_in_time(time_string, wpt->creation_time, wpt->microseconds, XML_LONG_TIME);
+ if (time_string[0]) {
+ gbfprintf(fout, " timestamp=\"%s\"", time_string);
+ }
+}
+
+static void
+xol_write_string(const char *name, const char *str)
+{
+ if (str && *str) {
+ char *temp = strenquote(str, '"');
+ gbfprintf(fout, " %s=%s", name, temp);
+ xfree(temp);
+ }
+}
+
+static void
+xol_waypt_bound_calc(const waypoint *wpt)
+{
+ waypt_add_to_bounds(&all_bounds, wpt);
+}
+
+static void
+xol_wr_init(const char *fname)
+{
+ fout = gbfopen(fname, "w", MYNAME);
+
+ space = 1;
+ waypt_init_bounds(&all_bounds);
+ short_h = mkshort_new_handle();
+
+ setshort_length(short_h, 1024); /* ??? */
+ setshort_badchars(short_h, "\r\n\t");
+ setshort_mustupper(short_h, 0);
+ setshort_mustuniq(short_h, 1);
+ setshort_whitespace_ok(short_h, 1);
+ setshort_repeating_whitespace_ok(short_h, 1);
+ setshort_defname(short_h, "Waypoint");
+}
+
+static void
+xol_wr_deinit(void)
+{
+ mkshort_del_handle(&short_h);
+ gbfclose(fout);
+}
+
+static void
+xol_waypt_disp_cb(const waypoint *wpt)
+{
+ double x, y;
+ char *name;
+
+ name = wpt->shortname;
+ if ((name == NULL) || (*name == '\0') || global_opts.synthesize_shortnames)
+ name = mkshort_from_wpt(short_h, wpt);
+ else
+ name = mkshort(short_h, name);
+
+ if (! GPS_Math_WGS84_To_CH1903_NGEN(wpt->latitude, wpt->longitude, &x, &y))
+ xol_fatal_outside(wpt);
+
+ gbfprintf(fout, "%*s<shape type=\"waypoint\"", space++*2, "");
+ xol_write_string("name", name);
+ xol_write_string("comment", wpt->notes);
+ xol_write_string("icon", wpt->icon_descr);
+ if (wpt->creation_time) xol_write_time(wpt);
+ if (wpt->altitude != unknown_alt) gbfprintf(fout, " alt=\"%.f\"", wpt->altitude);
+ gbfprintf(fout, ">\n");
+
+ gbfprintf(fout, "%*s<points>\n", space++*2, "");
+ gbfprintf(fout, "%*s<point x=\"%.f\" y=\"%.f\"/>\n", space*2, "", x, y);
+ gbfprintf(fout, "%*s</points>\n", --space*2, "");
+ gbfprintf(fout, "%*s</shape>\n", --space*2, "");
+
+ xfree(name);
+}
+
+static void
+xol_track_hdr_disp_cb(const route_head *trk)
+{
+ gbfprintf(fout, "%*s<shape type=\"polyline\"", space++*2, "");
+ xol_write_string("name", trk->rte_name);
+ gbfprintf(fout, " lineSize=\"3\" lineColor=\"#e60000\" lineStyle=\"solid\">\n");
+ gbfprintf(fout, "%*s<waypoints>\n", space++*2, "");
+}
+
+static void
+xol_track_tlr_disp_cb(const route_head *trk)
+{
+ gbfprintf(fout, "%*s</waypoints>\n", --space*2, "");
+ gbfprintf(fout, "%*s</shape>\n", --space*2, "");
+}
+
+static void
+xol_trkpt_disp_cb(const waypoint *wpt)
+{
+ double x, y;
+
+ if (! GPS_Math_WGS84_To_CH1903_NGEN(wpt->latitude, wpt->longitude, &x, &y))
+ xol_fatal_outside(wpt);
+
+ gbfprintf(fout, "%*s<shape type=\"waypoint\"", space++*2, "");
+ if (wpt->creation_time) xol_write_time(wpt);
+ if (wpt->altitude != unknown_alt) gbfprintf(fout, " alt=\"%.f\"", wpt->altitude);
+ gbfprintf(fout, ">\n");
+ gbfprintf(fout, "%*s<points>\n", space++*2, "");
+ gbfprintf(fout, "%*s<point x=\"%.f\" y=\"%.f\"/>\n", space*2, "", x, y);
+ gbfprintf(fout, "%*s</points>\n", --space*2, "");
+ gbfprintf(fout, "%*s</shape>\n", --space*2, "");
+}
+
+static void
+xol_write(void)
+{
+ double x, y;
+
+ waypt_disp_all(xol_waypt_bound_calc);
+ track_disp_all(NULL, NULL, xol_waypt_bound_calc);
+
+ if (! GPS_Math_WGS84_To_CH1903_NGEN(
+ (all_bounds.min_lat + all_bounds.max_lat) / 2,
+ (all_bounds.min_lon + all_bounds.max_lon) / 2, &x, &y)) {
+ gbfprintf(fout, "#####\n");
+ fatal(MYNAME ": At least one point is outside of convertable area \"%s\"!\n",
+ gt_get_mps_grid_longname(grid_swiss, MYNAME));
+ }
+
+ gbfprintf(fout, "<?xml version=\"1.0\" encoding=\"%s\"?>\n", global_opts.charset_name);
+ gbfprintf(fout, "<overlays>\n");
+ gbfprintf(fout, "%*s<overlay version=\"1.0\">\n", space++*2, "");
+ gbfprintf(fout, "%*s<center x=\"%.f\" y=\"%.f\"/>\n", space*2, "", x, y);
+ gbfprintf(fout, "%*s<shapes>\n", space++*2, "");
+ waypt_disp_all(xol_waypt_disp_cb);
+ track_disp_all(xol_track_hdr_disp_cb, xol_track_tlr_disp_cb, xol_trkpt_disp_cb);
+ gbfprintf(fout, "%*s</shapes>\n", --space*2, "");
+ gbfprintf(fout, "%*s</overlay>\n", --space*2, "");
+ gbfprintf(fout, "</overlays>\n");
+}
+
+ff_vecs_t xol_vecs = {
+ ff_type_file,
+ { ff_cap_read | ff_cap_write, /* waypoints */
+ ff_cap_read | ff_cap_write, /* tracks */
+ ff_cap_none }, /* routes */
+ xol_rd_init,
+ xol_wr_init,
+ xol_rd_deinit,
+ xol_wr_deinit,
+ xol_read,
+ xol_write,
+ NULL,
+ xol_args,
+ CET_CHARSET_UTF8, 0
+};